package com.berchen.数据结构.单链表;

import com.berchen.数据结构.栈.ArrayStack;

/**
 * 计算器
 */
public class Calculator {

    /**
     * 计算
     * 思路：
     *  创建两个栈 一个数栈 一个符号栈
     *     依次读取字符串中的字符
     *      如果是数字就压入数栈中
     *      如果是符号：
     *          1）符号栈为空，直接入栈。
     *          2）符号栈不为空，
     *              2.1）当前符号 <= 符号栈栈顶符号优先级 取出数据栈中两个数据和符号栈中的一个符号进行计算，然后将结果压入数栈，将当前符号压入符号栈中。
     *              2.2）当前符号 > 符号栈栈顶符号优先级，直接压入符号栈
     *
     * @return
     */
    public Integer calculator(String bds){

        if(bds==null||bds.length()<=0){
            return null;
        }
        char[] chars = bds.toCharArray();

        // 创建两个栈
        ArrayStack numStack=new ArrayStack(bds.length());
        ArrayStack prioStack=new ArrayStack(bds.length());
        StringBuffer  sb=new StringBuffer();
        for(int i =0;i<bds.length();i++){
            char ch=chars[i];
            if(isPrio(ch)){ // 是运算符

                // 1.将sb中的数字压入数栈中
                numStack.push(Integer.parseInt(sb.toString()));
                // 清空sb
                sb.delete(0,sb.length());
                // 2 判断符号栈是否为空
                if(prioStack.isEmpty()){    // 符号栈为空
                    prioStack.push(ch);
                }else { // 符号栈不未空

                    // 2.1 当前符号优先级 <= 栈顶符号优先级
                    if(getPriority(ch)<= getPriority(prioStack.peek())){
                        // 2.1.1 数栈两个数 弹出进行计算并且压入数栈中
                        numStack.push(calculate(numStack.pop(),numStack.pop(),(char) prioStack.pop()));
                        // 2.1.2 当前符号压入栈
                        prioStack.push(ch);
                    }else {
                        // 2.2 当前符号优先级 >  栈顶符号优先级
                        prioStack.push(ch);
                    }
                }
            }else{ // 不是运算符
                sb.append(ch);
                // 如果这是最后一个字符
                // 1.将sb中的数字压入数栈中
                if(i==chars.length-1) {
                    numStack.push(Integer.parseInt(sb.toString()));
                    while (!prioStack.isEmpty()) {
                        numStack.push(calculate(numStack.pop(), numStack.pop(), (char) prioStack.pop()));
                    }
                }
            }
        }
        return numStack.pop();
    }
    /**
     * 获取运算符的优先级
     * @param prio
     * @return
     */
    private int getPriority(int prio){

        if(prio=='*'||prio=='/'){
            return 1;
        }
        else if(prio=='+'||prio=='-'){
            return 0;
        }
        return -1;
    }

    /**
     * 判断是否是运算符
     * @param prio
     * @return
     */
    private boolean isPrio(int prio){
        return prio=='+'||prio=='-'||prio=='*'||prio=='/';
    }

    /**
     * 计算两个数的结果
     * @param num1 表达式后面的数
     * @param num2 表达式前面的数
     * @param prio 运算符
     * @return
     */
    private Integer calculate(int num1,int num2,char prio){
        Integer result;
        switch (prio){
            case '*':
                result=num1*num2;
                break;
            case '/':
                result=num2/num1;
                break;
            case '+':
                result=num1+num2;
                break;
            case '-':
                result=num2-num1;
                break;
            default:
                result=null;
                break;
        }
        return result;
    }
}
